{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<img src=\"https://raw.githubusercontent.com/Qiskit/qiskit-tutorials/master/images/qiskit-heading.png\" alt=\"Note: In order for images to show up in this jupyter notebook you need to select File => Trusted Notebook\" width=\"500 px\" align=\"left\">"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Elementary arithmetic operations\n",
    "In this tutorial, we are going to provide a construction of quantum networks effecting basic arithmetic operations, covering from addition to modular exponentiation, providing some executable examples using the simulator and five qubit device.\n",
    "\n",
    "\\begin{align}\n",
    "Plain\\; addition \\rightarrow Modular\\; addition \\rightarrow Modular\\; multiplication \\rightarrow Modular\\; exponentiation\n",
    "\\end{align}\n",
    "\n",
    "### Contributors\n",
    "\n",
    "Carlos Bravo Prieto\n",
    "\n",
    "## Introduction\n",
    "Nowadays, there is no known efficient classical algorithm for factoring. In the past years, the mathematician and MIT professor Peter Shor discovered an efficient algorithm for factoring large numbers using quantum effects, showing the potential power of quantum computation. \n",
    "There is a lot of interest in an efficient factoring algorithm, because most of the modern encryption is based on the impossibility to factorize large numbers. Therefore, Shor's algorithm could represent the fall of the actual cryptography.\n",
    "\n",
    "Shor's algorithm uses the quantum fourier transform to find the order $r$ of a randomly chosen number $x$ in the multiplicative group. This is done by exponentiating $x$ modulo $N$. Here, we focus in the quantum modular exponentiation which seems to be the most difficult part. Although the quantum modular exponentiation does not represent any speed up respect their classical analog, it has to be done in order to implement the quantum Shor's algorithm.\n",
    "\n",
    "## Plain addition\n",
    "Our first step is to build the most basic operation, the plain addition, which can be written as\n",
    "\n",
    "\\begin{align}\n",
    "|a, b \\rangle \\, \\rightarrow \\, |a, a+b \\rangle \\,.\n",
    "\\end{align}\n",
    "\n",
    "To prevent overflows, if $a$ and $b$ are encoded in $n$ qubits, the second register must be of size $n+1$. We will provisionally write the carries of the addition in a temporary register of size $n-1$ initially in state $|0\\rangle$. The operation of the plain addition can be understood as:\n",
    "1. First we compute the most significant bit of the result $a + b$. We have to compute all the carries $c_i$ through\n",
    "the relation $c_i$ $\\leftarrow$ $a_i$ AND $b_i$ AND $c_{i−1}$, where $a_i$, $b_i$ and $c_i$ represent the $i$th qubit of the first, second and temporary register respectively.\n",
    "2. Finally we reverse all these operations, except for the last one which computed the leading bit of the\n",
    "result. This way we can reuse the same temporary register if we require repeated additions. Meanwhile we are doing the resetting process, the other qubits of the result are computed through the relation $b_i$ $\\leftarrow$ $a_i$ XOR $b_i$ XOR $c_{i−1}$.\n",
    "\n",
    "The total number of qubits needed is $3n$.\n",
    "\n",
    "![Plain_addition network](plain_addition_network1.png)\n",
    "\n",
    "With this figure we seek a generalization of the algorithm, but the first carry qubit $c_0$ is not really needed, because the value will always be $0$.\n",
    "\n",
    "### Implementation in IBM Q quantum device. Example 1.\n",
    "We are going to start with the easiest example, the implementation of the plain addition of two one-qubit numbers $a$ and $b$. This program can be executed a 5-qubit device."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "# importing Qiskit\n",
    "from qiskit import Aer, IBMQ, execute\n",
    "from qiskit.backends.ibmq import least_busy\n",
    "from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit\n",
    "\n",
    "# import basic plotting tools\n",
    "from qiskit.tools.visualization import plot_histogram\n",
    "from qiskit.tools.qcvv.tomography import marginal_counts"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "IBMQ.load_accounts()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Use local qasm simulator\n",
    "# backend = Aer.get_backend('qasm_simulator')\n",
    "\n",
    "# Use the IBM Quantum Experience\n",
    "backend = least_busy(IBMQ.backends(simulator=False))\n",
    "\n",
    "# Use the IBM qasm simulator\n",
    "# backend = IBMQ.get_backend('ibmq_qasm_simulator')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "First let's define the plain addition algorithm for two one-qubit numbers $a$ and $b$. We implement the quantum plain addition algorithm based on the previous figure. We also define a function that creates those initial states (assuming that our input in Qiskit code is integer). We have to build the Toffoli gate from the elementary gates of the quantum computer."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "# quantum plain addition algorithm for 1-qubit numbers    \n",
    "def addition_1bit(circuit, q):\n",
    "    circuit.h(q[2])\n",
    "    circuit.cx(q[1], q[2])\n",
    "    circuit.tdg(q[2])\n",
    "    circuit.cx(q[0], q[2])\n",
    "    circuit.t(q[2])\n",
    "    circuit.cx(q[1], q[2])\n",
    "    circuit.tdg(q[2])\n",
    "    circuit.cx(q[0], q[2])\n",
    "    circuit.t(q[2])\n",
    "    circuit.h(q[2])\n",
    "    circuit.t(q[1])\n",
    "    circuit.cx(q[0], q[1])\n",
    "    circuit.t(q[0])\n",
    "    circuit.tdg(q[1])\n",
    "    \n",
    "# n-qubit number input state\n",
    "def number_state(circuit, q, a, b):\n",
    "    if a == 1:\n",
    "        circuit.x(q[0]) # q[0] contains the value of a\n",
    "    if b == 1:\n",
    "        circuit.x(q[1]) # q[1] contain the value of b"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's now implement the plain addition of two one-qubit numbers $a+b$, for instance $1+1$, that should return $2 \\,(10)$.\n",
    "\n",
    "In the Quantum Experience composer this circuit would look like:\n",
    "\n",
    "![Composer_circuit_1+1](1+1.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "COMPLETED\n",
      "{'time': 18.4138400554657, 'counts': {'00': 161, '10': 499, '01': 165, '11': 199}, 'date': '2018-10-12T19:07:51.304Z'}\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Backend: ibmq_16_melbourne\n",
      "Highest probability outcome: 2\n"
     ]
    }
   ],
   "source": [
    "# we define the values (0 or 1)\n",
    "a = 1                 \n",
    "b = 1\n",
    "\n",
    "# one single quantum register which contains 'a' (1 qubit) and 'b' (2 qubits)\n",
    "q = QuantumRegister(3, name=\"q\") # 3 qubits\n",
    "# clasical register\n",
    "c = ClassicalRegister(2, name=\"cr\") # 2 bits\n",
    "\n",
    "# quantum circuit involving the quantum register and the classical register\n",
    "add1bit_circuit = QuantumCircuit(q ,c, name=\"add\")\n",
    "\n",
    "# create the state containing a and b\n",
    "number_state(add1bit_circuit, q, a, b)\n",
    "\n",
    "# addition\n",
    "addition_1bit(add1bit_circuit, q)\n",
    "\n",
    "# measurements to see the result, which has been written in b (q[1]q[2])\n",
    "add1bit_circuit.measure(q[1], c[0])\n",
    "add1bit_circuit.measure(q[2], c[1])\n",
    "\n",
    "# compile and execute the quantum program in the backend\n",
    "result = execute(add1bit_circuit, backend=backend, shots=1024).result()\n",
    "\n",
    "# show the results\n",
    "print(result)\n",
    "print(result.get_data(add1bit_circuit))\n",
    "counts = marginal_counts(result.get_counts(add1bit_circuit), [0, 1])\n",
    "plot_histogram(counts)\n",
    "print(\"Backend:\", backend.name())\n",
    "print(\"Highest probability outcome: {}\".format(int(max(counts, key = lambda x: counts[x]).replace(\" \", \"\"), 2)))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We see that the highest probability outcome is $2 \\;(10)$ when we execute the code on IBM Q quantum device.\n",
    "\n",
    "### Implementation in the quantum simulator. Example 2.\n",
    "The second example is the implementation of the plain addition of two $n$-qubit numbers $a$ and $b$. This program can be executed in the quantum simulator."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "First let's define different modules that we are going to use repeatedly, as well as the plain addition algorithm for two $n$-qubit numbers."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Use local qasm simulator\n",
    "backend = Aer.get_backend('qasm_simulator')\n",
    "\n",
    "# Use the IBM qasm simulator\n",
    "# backend = IBMQ.get_backend('ibmq_qasm_simulator')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "def carry(circuit, q0, q1, q2, q3):\n",
    "    \"carry module\"\n",
    "    circuit.ccx(q1, q2, q3)\n",
    "    circuit.cx(q1, q2)\n",
    "    circuit.ccx(q0, q2, q3)\n",
    "    \n",
    "def carry_inv(circuit, q0, q1, q2, q3):\n",
    "    \"carry module but running backwards\"\n",
    "    circuit.ccx(q0, q2, q3)\n",
    "    circuit.cx(q1, q2)\n",
    "    circuit.ccx(q1, q2, q3)\n",
    "    \n",
    "def summation(circuit, q0, q1, q2):\n",
    "    \"summation module\"\n",
    "    circuit.cx(q1, q2)\n",
    "    circuit.cx(q0, q2)\n",
    "    \n",
    "# quantum plain addition algorithm for n-qubit numbers    \n",
    "def addition_nbit(circuit, qa, qb, qcar, n):\n",
    "    if n == 1:\n",
    "        circuit.ccx(qa[0], qb[0], qb[1])\n",
    "        circuit.cx(qa[0], qb[0])\n",
    "    else:\n",
    "        circuit.ccx(qa[0], qb[0], qcar[0])\n",
    "        circuit.cx(qa[0], qb[0])\n",
    "        for i in range(n-2):\n",
    "            carry(circuit, qcar[i], qa[i+1], qb[i+1], qcar[i+1])\n",
    "        carry(circuit, qcar[n-2], qa[n-1], qb[n-1], qb[n])\n",
    "        circuit.cx(qa[n-1], qb[n-1])\n",
    "        for i in range(n-1, 1, -1):\n",
    "            summation(circuit, qcar[i-1], qa[i], qb[i])\n",
    "            carry_inv(circuit, qcar[i-2], qa[i-1], qb[i-1], qcar[i-1])\n",
    "        summation(circuit, qcar[0], qa[1], qb[1])\n",
    "        circuit.cx(qa[0], qb[0])\n",
    "        circuit.ccx(qa[0], qb[0], qcar[0])\n",
    "        circuit.cx(qa[0], qb[0])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now we are going to define a function that creates the states containing $a$ and $b$. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "# n-qubit number input state\n",
    "def number_state(circuit, q, x, n):\n",
    "    # integer to binary\n",
    "    x = \"{0:b}\".format(x)\n",
    "    x = x.zfill(n)\n",
    "    # creating the state\n",
    "    for i in range(n):\n",
    "        if int(x[n-1-i]) == 1:\n",
    "            circuit.x(q[i])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's now implement the plain addition of two numbers $a+b$, for instance $9+14$, that should return $23$ $(10111)$:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "COMPLETED\n",
      "{'creg_labels': 'cr[5]', 'additionalData': {'seed': 587126267}, 'versionSimulationRun': 'IBM_Q_Simulator:CPU-v0.1.b5cdd73\\n', 'time': 3.87647, 'counts': {'10111': 1024}, 'date': '2018-10-12T19:08:12.760Z'}\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYgAAAEaCAYAAAAL7cBuAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDMuMC4wLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvqOYd8AAAFWJJREFUeJzt3X+wnmV95/H3hwBafiwaCAicIGjCIAIucmBhtfw0JcFuYnfbSrpCUTBLVmRX22Xo7kIX2u3Wsq5tR5SmFk1wKmC1ktHwY0ZlkGKQRJHyY1iyiOaEKEECDkUE5Lt/PE/o48l9cs5z8pznOYnv18yZc9/XfZ3zfM8Mwyf3dV33daeqkCRptF0GXYAkaXoyICRJjQwISVIjA0KS1MiAkCQ1MiAkSY36EhBJrk3yRJL7x7j+75Pc1/66K8lb+lGXJGls/bqD+AwwfxvXvwecUlXHAH8ELOtHUZKkse3ajw+pqjuSHLqN63d1nK4Ghqa6JknStvUlILp0PnDzWBeTLAGWAOy5557HHXHEEf2qS5J2CmvXrn2yqmaN129aBUSS02gFxNvH6lNVy2gPQQ0PD9eaNWv6VJ0k7RySfH8i/aZNQCQ5BvgUsKCqfjzoeiTpl920WOaa5BDgi8A5VfV/B12PJKlPdxBJPgecCuyXZAT4Q2A3gKq6Brgc2Bf4RBKAl6pquB+1SZKa9WsV0+Jxrl8AXNCPWiRJEzMthpgkSdOPASFJamRASJIaGRCSpEYGhCSpkQEhSWpkQEiSGhkQkqRGBoQkqZEBIUlqZEBIkhoZEJKkRgaENAHve9/72H///TnqqKMar1cVF198MXPmzOGYY47h29/+9ivXli9fzty5c5k7dy7Lly9/pX3t2rUcffTRzJkzh4svvpiqmvK/Q+qGASFNwHnnncctt9wy5vWbb76ZRx55hEceeYRly5axdOlSAJ566imuuOIK7r77br71rW9xxRVXsHnzZgCWLl3KsmXLXvm5bf1+aRAMCGkCTj75ZGbOnDnm9Ztuuolzzz2XJJx44ok8/fTTbNy4kVtvvZV58+Yxc+ZMXvva1zJv3jxuueUWNm7cyE9+8hNOOukkknDuuefypS99qY9/kTQ+A0LqgQ0bNjB79uxXzoeGhtiwYcM224eGhrZql6YTA0Lqgab5gyRdt0vTiQEh9cDQ0BDr169/5XxkZISDDjpom+0jIyNbtUvTiQEh9cDChQtZsWIFVcXq1avZZ599OPDAAznzzDO57bbb2Lx5M5s3b+a2227jzDPP5MADD2Tvvfdm9erVVBUrVqxg0aJFg/4zpF/Ql3dSSzu6xYsXc/vtt/Pkk08yNDTEFVdcwYsvvgjAhRdeyFlnncWqVauYM2cOe+yxB5/+9KcBmDlzJpdddhnHH388AJdffvkrk92f/OQnOe+88/jpT3/KggULWLBgwWD+OGkM2ZHXXg8PD9eaNWsGXYYk7VCSrK2q4fH6OcQkSWpkQEiSGhkQkqRGBoQkqZEBIUlqZEBIkhr1JSCSXJvkiST3j3E9Sf4yybok9yV5az/qkiSNrV93EJ8B5m/j+gJgbvtrCfDJPtQkSdqGvgREVd0BPLWNLouAFdWyGnhNkgP7UZskqdl02WrjYGB9x/lIu23j6I5JltC6y+CQQw6Z9AceeulXJv2zkjRoj/3pO6f8M6bLJHXTPseNe4BU1bKqGq6q4VmzZk1xWZL0y2u6BMQIMLvjfAh4fEC1SJKYPgGxEji3vZrpROCZqtpqeEmS1D99mYNI8jngVGC/JCPAHwK7AVTVNcAq4CxgHfAc8N5+1CVJGltfAqKqFo9zvYAP9KMWSdLETJchJknSNGNASJIaGRCSpEYGhCSpkQEhSWpkQEiSGhkQkqRGBoQkqZEBIUlqZEBIkhoZEJKkRgaEJKmRASFJamRASJIaGRCSpEYGhCSpkQEhSWpkQEiSGhkQkqRGBoQkqZEBIUlqZEBIkhoZEJKkRgaEJKmRASFJamRASJIaGRCSpEYGhCSpUd8CIsn8JA8nWZfk0obrhyT5epLvJLkvyVn9qk2StLW+BESSGcDVwALgSGBxkiNHdfvvwI1VdSxwNvCJftQmSWrWrzuIE4B1VfVoVb0AXA8sGtWngH/RPt4HeLxPtUmSGvQrIA4G1necj7TbOv0P4D1JRoBVwAebflGSJUnWJFmzadOmqahVkkT/AiINbTXqfDHwmaoaAs4CrkuyVX1VtayqhqtqeNasWVNQqiQJ+hcQI8DsjvMhth5COh+4EaCqvgm8GtivL9VJkrYy4YBIMivJXu3jGUnem+Tcpn/lN7gHmJvksCS705qEXjmqzw+AM9q//020AsIxJEkakG7uIL4MzG0f/0/g94EPAx8d7wer6iXgIuBW4CFaq5UeSHJlkoXtbr8HvD/Jd4HPAedV1ehhKElSn+zaRd/DgXvbx+8B/jXwLPAA8KHxfriqVtGafO5su7zj+EHgbV3UI0maQt0ExM+B3ZMcDjxTVT9oDy/tNTWlSZIGqZuAuJnWJPK+tJ5jgNZDbxt6XZQkafC6CYgLgN8FXgSua7ftR+v5BUnSTmbCAVFVPwOWtYeVDgA2VtXtU1WYJGmwulnm+pokfws8D6xrty1M8sdTVZwkaXC6WeZ6DfAM8HrghXbbN4F397ooSdLgdTMHcQZwUFW9mKQAqmpTkv2npjRJ0iB1cwfxDKO2vkhyCLCxpxVJkqaFbgLiU8AXkpwG7JLkJGA5raEnSdJOppshpo/QmqC+GtgNuBb4K+AvpqAuSdKAdbPMtYA/b39JknZy2wyIJCdX1R3t49PH6ldVX+t1YZKkwRrvDuITwFHt478Zo08Bb+hZRZKkaWGbAVFVR3UcHzb15UiSpotunqS+aYz2L/auHEnSdNHNMtfTxmg/tQd1SJKmmXFXMSW5sn24e8fxFm8Avt/zqiRJAzeRZa6z29936TiG1uT0etzuW5J2SuMGRFW9FyDJXVX111NfkiRpOhjvOYhDq+qx9ulXkzQuZ62qR3tdmCRpsMa7g/hHYO/28Tpaw0oZ1aeAGT2uS5I0YOM9B7F3x3E3K54kSTs4/6cvSWo03hzEN2gNIW1TVZ3cs4okSdPCeHMQn+pLFZKkaWe8OYjl/SpEkjS9jDfEdE5VXdc+ft9Y/arq2l4XJkkarPGGmBYD17WPzxmjT9F6u9w2JZlP6+1zM4BPVdWfNvT5bVpPZhfw3ar6nfF+ryRpaow3xHRWx/FYm/WNK8kMWq8qnQeMAPckWVlVD3b0mQv8AfC2qtqcZP/Jfp4kaft1805qkrwGeCdwEPA48JWqenoCP3oCsG7LE9dJrgcWAQ929Hk/cHVVbQaoqie6qU2S1FvdvA/idOAx4GLgeOCDwGNJzpjAjx9Ma2O/LUbabZ0OBw5P8g9JVreHpJrqWJJkTZI1mzZtmmj5kqQudXMH8XFgSVXduKUhyW/RGjo6YpyfHb09B2z9fMWuwFxa75cYAr6R5KjRdyhVtQxYBjA8PDzuMxqSpMnp5knqg4AvjGr7e+B1E/jZEX5xq/AhWkNUo/vcVFUvVtX3gIdpBYYkaQC6CYgVwAdGtS1tt4/nHmBuksOS7A6cDawc1edLtN9al2Q/WkNO7hIrSQPSzVYbuwBLk1wCbKA1h3AAsHq8D6mql5JcBNxKa5nrtVX1QPsNdWuqamX72q8leRD4OfBfqurHk/y7JEnbqdutNib9wqCqWgWsGtV2ecdxAR9uf0mSBsytNiRJjbp9DuIAWs807EfHyiS32pCknc+EAyLJu4DPAo8AbwYeAI4C7mQCW21IknYs3axi+mPgvVV1LPBP7e9LgLVTUpkkaaC6CYhDqurzo9qWA+f2sB5J0jTRTUA80Z6DgNYWGycBb6S1bFWStJPpJiD+Gnh7+/hjwNeB7wKf6HVRkqTBm/AkdVV9pON4RZLbgT2r6qGpKEySNFjdLnOdAZzIP2/3Pe5T1JKkHVM3y1yPobVf0qtpbaw3BDyf5Deq6rtTVJ8kaUC6mYO4ltbW3gdX1Qm09mL6OD4DIUk7pW4C4nDgz9t7Jm3ZO+kvcEtuSdopdRMQq4CFo9r+DfCV3pUjSZouxtvu+zr+ebvvGcD1SdbSen3obOA44KYprVCSNBDjTVKvG3V+f8fxg7Te4SBJ2gmNt933Ff0qRJI0vXT7HMRpwDm0VjBtAD5bVV+bisIkSYM14UnqJBcANwA/BL4IbAT+Nsn7p6g2SdIAdXMHcQkwr/OhuCQ3AF9gO15FKkmanrpZ5rovrYnpTg8DM3tXjiRpuugmIO4E/k+SPQCS7AlcBdw1FYVJkgarm4C4EDgaeCbJj4CngbcA/2EqCpMkDdaE5iCSBPgV4B3A62jv5lpVI1NYmyRpgCYUEFVVSf4R2LsdCgaDJO3kuhli+g6tDfskSb8EulnmejtwS5LP0NqLacseTVSVW35L0k6mm4B4G/A94JRR7YXvhJCknc64Q0xJ9kjyJ8CzwB3A/Ko6rePr9Il8UJL5SR5Osi7Jpdvo95tJKsnwhP8KSVLPTWQO4uO03vvwEPDvgP/d7Ye032V9NbAAOBJYnOTIhn57AxcDd3f7GZKk3ppIQCwAfq2qLmkf//okPucEYF1VPVpVLwDXA4sa+v0R8GfA85P4DElSD00kIPasqo0AVbUe2GcSn3MwrYntLUbaba9Iciwwu6q+vK1flGRJkjVJ1mzatGkSpUiSJmIik9S7trf5zhjnTGDL7zS0vbIKKskuwMeA88YrpqqWAcsAhoeHa5zukqRJmkhAPMEvrlL68ajzAt4wzu8YofWK0i2GgMc7zvcGjgJubz20zeuAlUkWVtWaCdQoSeqxcQOiqg7twefcA8xNchitFw2dDfxOx2c8A+y35TzJ7cDvGw6SNDjdPEk9aVX1EnARrXdYPwTcWFUPJLkyycJ+1CBJ6k5XrxzdHlW1Clg1qu3yMfqe2o+aJElj68sdhCRpx2NASJIaGRCSpEYGhCSpkQEhSWpkQEiSGhkQkqRGBoQkqZEBIUlqZEBIkhoZEJKkRgaEJKmRASFJamRASJIaGRCSpEYGhCSpkQEhSWpkQEiSGhkQkqRGBoQkqZEBIUlqZEBIkhoZEJKkRgaEJKmRASFJamRASJIaGRCSpEZ9C4gk85M8nGRdkksbrn84yYNJ7kvy1SSv71dtkqSt9SUgkswArgYWAEcCi5McOarbd4DhqjoG+Dvgz/pRmySpWb/uIE4A1lXVo1X1AnA9sKizQ1V9vaqea5+uBob6VJskqUG/AuJgYH3H+Ui7bSznAzc3XUiyJMmaJGs2bdrUwxIlSZ36FRBpaKvGjsl7gGHgqqbrVbWsqoaranjWrFk9LFGS1GnXPn3OCDC743wIeHx0pyTvAP4bcEpV/axPtUmSGvTrDuIeYG6Sw5LsDpwNrOzskORY4K+AhVX1RJ/qkiSNoS8BUVUvARcBtwIPATdW1QNJrkyysN3tKmAv4PNJ7k2ycoxfJ0nqg34NMVFVq4BVo9ou7zh+R79qkSSNzyepJUmNDAhJUiMDQpLUyICQJDUyICRJjQwISVIjA0KS1MiAkCQ1MiAkSY0MCElSIwNCktTIgJAkNTIgJEmNDAhJUiMDQpLUyICQJDUyICRJjQwISVIjA0KS1MiAkCQ1MiAkSY0MCElSIwNCktTIgJAkNTIgJEmNDAhJUiMDQpLUyICQJDXqW0AkmZ/k4STrklzacP1VSW5oX787yaH9qk2StLW+BESSGcDVwALgSGBxkiNHdTsf2FxVc4CPAR/pR22SpGb9uoM4AVhXVY9W1QvA9cCiUX0WAcvbx38HnJEkfapPkjTKrn36nIOB9R3nI8C/GqtPVb2U5BlgX+DJzk5JlgBL2qfPJnl4SiqWtt9+jPrvV+qVbN8Yy+sn0qlfAdF0J1CT6ENVLQOW9aIoaSolWVNVw4OuQ5qsfg0xjQCzO86HgMfH6pNkV2Af4Km+VCdJ2kq/AuIeYG6Sw5LsDpwNrBzVZyXwu+3j3wS+VlVb3UFIkvqjL0NM7TmFi4BbgRnAtVX1QJIrgTVVtRL4G+C6JOto3Tmc3Y/apCnkUKh2aPEf6ZKkJj5JLUlqZEBIkhoZEJKkRgaEJKmRASFJamRASJIaGRDSFOjcaDLJrm48qR2RASFNjT2SHAutB0WrqpLsYlhoR2JASFPjEmBtkpEkVyV5fVW93BEWuyV596CLlLbFgJCmxinAZcClwInAo0keSvKh9vX5wFWDKk6aCANC6rEkewF303pJ1mer6leBNwLXARcmeR64CfjoAMuUxuVeTNIUSDILoKo2JUnnzsRJTgduBl5bVc8NqkZpPP16YZD0S6WqNnUcF7RWNrWPTwEeMxw03XkHIfVZkl8Fnq+qewZdi7QtBoTUQ0neDDwHjFTVix3t8QVY2tEYEFKPtF+Vuw74B+Au4N72+RMdw0xHAD+qqs0DK1SaIOcgpN55F603Jv4Q+G3gt4AHgLuT3N8+vhM4HTAgNO0ZEFLvHAb8fVX9Xvtp6XcCi4ClwCbgJeDlqrpvgDVKE+YQk9QjSXYH3gQ8OGr+4QDgBODzwJ9U1ZUDKlHqigEh9UDTJHSSXQCq6uX2+fPAkVX16ABKlLrmEJPUA+39lWa0j3/e/v7ylutJjgauMxy0I/EOQtpOSfaklRHPdbS9cvfgElftqNyLSdp+fwDck+SjSU6DVjB03EHskeTwwZUnTY53ENJ2SvID4FbgZeAI4HngG8CXq+reJBcAx1XV0gGWKXXNOQhpOyR5I7CG1k6t/4/WKqa3AscB85N8H3g38J6BFSlNkncQ0nZIMhM4ntbS1vXttlcDhwKH0HpY7jeqar+BFSlNkgEh9UCSXTpXLXW03wC8qqreNYCypO3iEJO0HZLsS2vu4cUku23ZY6lj5dJGYMUga5QmyzsIaZKSnA8sBN4BPEJrYvqbwFer6kftPvtW1Y8HV6U0eQaENAlJDgLuBz4IfA04FZgHvAV4Frisqu4YWIFSDxgQ0iQk+RBwVlXNG9V+APBfad1VnFFVPxxEfVIv+KCcNDl3A3sl+ZedjVX1o6r6T7S29j5nIJVJPWJASJNzL/A94JoklyR5a3t56xZDwE8HU5rUGw4xSZOU5FeADwAn0nrXw7O0/tG1K61nI47r3J9J2tEYENJ2SnI8cBKwP/AaWkFxTVU9Nsi6pO1lQEhdaIfBf6a1cunOqnq449qrqupnW74PrEipRwwIqQtJvgi8GbgH2AP4PrCaVlhsSPI64PKq+o8DLFPqCQNCmqD2C4FuBm4AHqa1Id+baA0tvUQrKN4FPFlV/3ZQdUq94lYb0sTtDiwHHq2qbwJ3tu8YjqW1g+sRwNtpTVBLOzzvIKQubdmYb/Sb4pIsAf5XVe07wPKknvE5CKlLW3Zt3RIOSdK+NBu4ZlB1Sb3mHYTUI0n2A/6pqnxATjsFA0KS1MghJklSIwNCktTIgJAkNTIgJEmNDAhJUqP/Dy9vA952IZPVAAAAAElFTkSuQmCC\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Backend: ibmq_qasm_simulator\n",
      "Highest probability outcome: 23\n"
     ]
    }
   ],
   "source": [
    "# we define the values\n",
    "a = 9                 \n",
    "b = 14\n",
    "\n",
    "# computing the number of qubits n needed\n",
    "n = len(\"{0:b}\".format(a))\n",
    "n2 = len(\"{0:b}\".format(b))\n",
    "if n2 > n:\n",
    "    n = n2\n",
    "    \n",
    "# classical register with n+1 bits.\n",
    "c = ClassicalRegister(n+1, name=\"cr\")\n",
    "# quantum registers\n",
    "qa = QuantumRegister(n, name=\"qa\") # a qubits\n",
    "qb = QuantumRegister(n+1, name=\"qb\") # b qubits\n",
    "# if n = 1, no need of carry register \n",
    "if n == 1:\n",
    "    qcar = 0\n",
    "    # quantum circuit involving the quantum registers and the classical register\n",
    "    addnbit_circuit = QuantumCircuit(qa, qb,c, name=\"add\")\n",
    "else:\n",
    "    qcar = QuantumRegister(n-1, name=\"qcar\") # carry qubits\n",
    "    # quantum circuit involving the quantum registers and the classical register\n",
    "    addnbit_circuit = QuantumCircuit(qa, qb, qcar,c, name=\"add\")\n",
    "\n",
    "# create the state containing a\n",
    "number_state(addnbit_circuit, qa, a, n)\n",
    "# create the state containing b\n",
    "number_state(addnbit_circuit, qb, b, n)\n",
    "\n",
    "# addition\n",
    "addition_nbit(addnbit_circuit, qa, qb, qcar, n)\n",
    "\n",
    "# measurements to see the result\n",
    "for i in range(n+1):\n",
    "    addnbit_circuit.measure(qb[i], c[i])\n",
    "\n",
    "# compile and execute the quantum program in the backend\n",
    "result = execute(addnbit_circuit, backend=backend, shots=1024).result()\n",
    "\n",
    "# show the results.\n",
    "print(result)\n",
    "print(result.get_data(addnbit_circuit))\n",
    "counts = result.get_counts(addnbit_circuit)\n",
    "plot_histogram(counts)\n",
    "print(\"Backend:\", backend.name())\n",
    "print(\"Highest probability outcome: {}\".format(int(max(counts, key = lambda x: counts[x]).replace(\" \", \"\"), 2)))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We indeed see that the only appearing outcome is $23\\,(10111)$ when we execute the code on local_qasm_simulator."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Modular addition\n",
    "As you may already expect, as we increase the complexity of the arithmetic operations we also increase the complexity of the circuit network. Our next goal is to build a network that effects\n",
    "\n",
    "\\begin{align}\n",
    "| a, b \\rangle\\, \\rightarrow \\, | a, a+b\\, mod \\,N \\rangle\n",
    "\\end{align}\n",
    "\n",
    "where $a+b < 2N$ (this condition is enough in order to build the following arithmetic operations). The approach consists essentially on taking the output of the plain adder network and then substracting $N$, depending on whether the value $a+b$ is bigger or smaller than $N$. In order to do so, we use a temporary qubit which indicates whether there has been an overflow in the substraction or not, and adding back $N$ depending on this. The last part of the network takes care of reseting every register (except the second register which contains the result) to its initial state.\n",
    "\n",
    "The total number of qubits needed is $5n + 2$.\n",
    "\n",
    "![Modular addition network](modular_addition_network1.png)\n",
    "\n",
    "### Implementation in the quantum simulator. Example 3.\n",
    "The third example is the implementation of the modular addition of two $n$-qubit numbers $a$ and $b$ (modulo $N$). This program can be executed in the quantum simulator."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now we define again the different modules that we are going to use repeatedly, as well as the modular addition algorithm for two $n$-qubit numbers. This time we also have to substract or use conditional adders (in order to substract $N$ or not), therefore we have to implement new modules such as the conditional plain addition or the plain substraction."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Use local qasm simulator\n",
    "backend = Aer.get_backend('qasm_simulator')\n",
    "\n",
    "# Use the IBM qasm simulator\n",
    "# backend = IBMQ.get_backend('ibmq_qasm_simulator')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "def carry(circuit, q0, q1, q2, q3):\n",
    "    \"carry module\"\n",
    "    circuit.ccx(q1, q2, q3)\n",
    "    circuit.cx(q1, q2)\n",
    "    circuit.ccx(q0, q2, q3)\n",
    "    \n",
    "def carry_inv(circuit, q0, q1, q2, q3):\n",
    "    \"carry module running backwards\"\n",
    "    circuit.ccx(q0, q2, q3)\n",
    "    circuit.cx(q1, q2)\n",
    "    circuit.ccx(q1, q2, q3)\n",
    "    \n",
    "def summation(circuit, q0, q1, q2):\n",
    "    \"summation module\"\n",
    "    circuit.cx(q1, q2)\n",
    "    circuit.cx(q0, q2)\n",
    "    \n",
    "def summation_inv(circuit, q0, q1, q2):\n",
    "    \"summation module running backwards\"\n",
    "    circuit.cx(q0, q2)\n",
    "    circuit.cx(q1, q2)\n",
    "\n",
    "# quantum plain addition algorithm for n-qubit numbers    \n",
    "def addition_nbit(circuit, qa, qb, qcar, n):\n",
    "    if n == 1:\n",
    "        circuit.ccx(qa[0], qb[0], qb[1])\n",
    "        circuit.cx(qa[0], qb[0])\n",
    "    else:\n",
    "        circuit.ccx(qa[0], qb[0], qcar[0])\n",
    "        circuit.cx(qa[0], qb[0])\n",
    "        for i in range(n-2):\n",
    "            carry(circuit, qcar[i], qa[i+1], qb[i+1], qcar[i+1])\n",
    "        carry(circuit, qcar[n-2], qa[n-1], qb[n-1], qb[n])\n",
    "        circuit.cx(qa[n-1], qb[n-1])\n",
    "        for i in range(n-1, 1, -1):\n",
    "            summation(circuit, qcar[i-1], qa[i], qb[i])\n",
    "            carry_inv(circuit, qcar[i-2], qa[i-1], qb[i-1], qcar[i-1])\n",
    "        summation(circuit, qcar[0], qa[1], qb[1])\n",
    "        circuit.cx(qa[0], qb[0])\n",
    "        circuit.ccx(qa[0], qb[0], qcar[0])\n",
    "        circuit.cx(qa[0], qb[0])\n",
    "    \n",
    "# quantum plain substraction algorithm for n-qubit numbers\n",
    "def subs_nbit(circuit, qa, qb, qcar, n):\n",
    "    \"same circuit as the plain addition but going backwards\"\n",
    "    if n == 1:\n",
    "        circuit.cx(qa[0], qb[0])\n",
    "        circuit.ccx(qa[0], qb[0], qb[1])\n",
    "    else:\n",
    "        circuit.cx(qa[0], qb[0])\n",
    "        circuit.ccx(qa[0], qb[0], qcar[0])\n",
    "        circuit.cx(qa[0], qb[0])\n",
    "        summation_inv(circuit, qcar[0], qa[1], qb[1])\n",
    "        for i in range(n-2):\n",
    "            carry(circuit, qcar[i], qa[i+1], qb[i+1], qcar[i+1])\n",
    "            summation_inv(circuit, qcar[i+1], qa[i+2], qb[i+2])\n",
    "        circuit.cx(qa[n-1], qb[n-1])\n",
    "        carry_inv(circuit, qcar[n-2], qa[n-1], qb[n-1], qb[n])\n",
    "        for i in range(n-2, 0, -1):\n",
    "            carry_inv(circuit, qcar[i-1], qa[i], qb[i], qcar[i])\n",
    "        circuit.cx(qa[0], qb[0])  \n",
    "        circuit.ccx(qa[0], qb[0], qcar[0])\n",
    "\n",
    "def cond_toffoli(circuit, qcond, q1, q2, q3):\n",
    "    \"toffoli gate conditioned by an external qubit\"\n",
    "    circuit.h(q3)\n",
    "    circuit.ccx(qcond, q2, q3)\n",
    "    circuit.tdg(q3)\n",
    "    circuit.ccx(qcond, q1, q3)\n",
    "    circuit.t(q3)\n",
    "    circuit.ccx(qcond, q2, q3)\n",
    "    circuit.tdg(q3)\n",
    "    circuit.ccx(qcond, q1, q3)\n",
    "    circuit.t(q3)\n",
    "    circuit.h(q3)\n",
    "    circuit.t(q2)\n",
    "    circuit.ccx(qcond, q1, q2)\n",
    "    circuit.t(q1)\n",
    "    circuit.tdg(q2)\n",
    "    circuit.ccx(qcond, q1, q2)\n",
    "    \n",
    "def cond_carry(circuit, q0, q1, q2, q3, qcond):\n",
    "    \"conditional carry module\"\n",
    "    cond_toffoli(circuit, qcond, q1, q2, q3)\n",
    "    circuit.ccx(qcond, q1, q2)\n",
    "    cond_toffoli(circuit, qcond, q0, q2, q3)\n",
    "    \n",
    "def cond_carry_inv(circuit, q0, q1, q2, q3, qcond):\n",
    "    \"conditional carry module running backwards\"\n",
    "    cond_toffoli(circuit, qcond, q0, q2, q3)\n",
    "    circuit.ccx(qcond, q1, q2)\n",
    "    cond_toffoli(circuit, qcond, q1, q2, q3)\n",
    "    \n",
    "def cond_summation(circuit, q0, q1, q2, qcond):\n",
    "    \"conditional summation module\"\n",
    "    circuit.ccx(qcond, q1, q2)\n",
    "    circuit.ccx(qcond, q0, q2)\n",
    "    \n",
    "def cond_summation_inv(circuit, q0, q1, q2, qcond):\n",
    "    \"conditional summation module running backwards\"\n",
    "    circuit.ccx(qcond, q0, q2)\n",
    "    circuit.ccx(qcond, q1, q2)\n",
    "    \n",
    "# quantum conditional plain addition algorithm for n-qubit numbers    \n",
    "def cond_addition_nbit(circuit, qa, qb, qcar, qcond, n):\n",
    "    \"plain addition algorithm conditioned by an external qubit\"\n",
    "    if n == 1:\n",
    "        cond_toffoli(circuit, qcond[0], qa[0], qb[0], qb[1])\n",
    "        circuit.ccx(qcond[0], qa[0], qb[0])\n",
    "    else:\n",
    "        cond_toffoli(circuit, qcond[0], qa[0], qb[0], qcar[0])\n",
    "        circuit.ccx(qcond[0], qa[0], qb[0])\n",
    "        for i in range(n-2):\n",
    "            cond_carry(circuit, qcar[i], qa[i+1], qb[i+1], qcar[i+1], qcond[0])\n",
    "        cond_carry(circuit, qcar[n-2], qa[n-1], qb[n-1], qb[n], qcond[0])\n",
    "        circuit.ccx(qcond[0], qa[n-1], qb[n-1])\n",
    "        for i in range(n-1, 1, -1):\n",
    "            cond_summation(circuit, qcar[i-1], qa[i], qb[i], qcond[0])\n",
    "            cond_carry_inv(circuit, qcar[i-2], qa[i-1], qb[i-1], qcar[i-1], qcond[0])\n",
    "        cond_summation(circuit, qcar[0], qa[1], qb[1], qcond[0])\n",
    "        circuit.ccx(qcond[0], qa[0], qb[0])\n",
    "        cond_toffoli(circuit, qcond[0], qa[0], qb[0], qcar[0])\n",
    "        circuit.ccx(qcond[0], qa[0], qb[0])\n",
    "\n",
    "# quantum conditional plain substraction algorithm for n-qubit numbers      \n",
    "def cond_subs_nbit(circuit, qa, qb, qcar, qcond, n):\n",
    "    \"same circuit as the conditional plain addition but going backwards\"\n",
    "    if n == 1:\n",
    "        circuit.ccx(qcond[0], qa[0], qb[0])\n",
    "        cond_toffoli(circuit, qcond[0], qa[0], qb[0], qb[1])\n",
    "    else:\n",
    "        circuit.ccx(qcond[0], qa[0], qb[0])\n",
    "        cond_toffoli(circuit, qcond[0], qa[0], qb[0], qcar[0])\n",
    "        circuit.ccx(qcond[0], qa[0], qb[0])\n",
    "        cond_summation_inv(circuit, qcar[0], qa[1], qb[1], qcond[0])\n",
    "        for i in range(n-2):\n",
    "            cond_carry(circuit, qcar[i], qa[i+1], qb[i+1], qcar[i+1], qcond[0])\n",
    "            cond_summation_inv(circuit, qcar[i+1], qa[i+2], qb[i+2], qcond[0])\n",
    "        circuit.ccx(qcond[0], qa[n-1], qb[n-1])\n",
    "        cond_carry_inv(circuit, qcar[n-2], qa[n-1], qb[n-1], qb[n], qcond[0])\n",
    "        for i in range(n-2, 0, -1):\n",
    "            cond_carry_inv(circuit, qcar[i-1], qa[i], qb[i], qcar[i], qcond[0])\n",
    "        circuit.ccx(qcond[0], qa[0], qb[0])  \n",
    "        cond_toffoli(circuit, qcond[0], qa[0], qb[0], qcar[0])\n",
    "        \n",
    "# quantum modular addition algorithm for n-qubit numbers \n",
    "def mod_addition_nbit(circuit, qa, qb, qN, qNtemp, qcar, qtemp, n):\n",
    "    addition_nbit(circuit, qa, qb, qcar, n)\n",
    "    subs_nbit(circuit, qN, qb, qcar, n)\n",
    "    circuit.x(qb[n])\n",
    "    circuit.cx(qb[n], qtemp[0])\n",
    "    circuit.x(qb[n])\n",
    "    cond_subs_nbit(circuit, qNtemp, qN, qcar, qtemp, n)\n",
    "    addition_nbit(circuit, qN, qb, qcar, n)\n",
    "    cond_addition_nbit(circuit, qNtemp, qN, qcar, qtemp, n)\n",
    "    subs_nbit(circuit, qa, qb, qcar, n)\n",
    "    circuit.cx(qb[n], qtemp[0])\n",
    "    addition_nbit(circuit, qa, qb, qcar, n)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now we define the function that creates the states containing $a$, $b$ and $N$. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "# n-qubit number input state\n",
    "def number_state(circuit, q, x, n):\n",
    "    # integer to binary\n",
    "    x = \"{0:b}\".format(x)\n",
    "    x = x.zfill(n)\n",
    "    # creating the state\n",
    "    for i in range(n):\n",
    "        if int(x[n-1-i]) == 1:\n",
    "            circuit.x(q[i])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's implement the modular addition of two numbers $a+b \\, mod \\, N$, for instance $2+3 \\,mod\\, 3$, that should return $2 \\, (010)$:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "COMPLETED\n",
      "{'creg_labels': 'cr[3]', 'additionalData': {'seed': 1872831481}, 'versionSimulationRun': 'IBM_Q_Simulator:CPU-v0.1.b5cdd73\\n', 'time': 32.561, 'counts': {'010': 1024}, 'date': '2018-10-12T19:09:32.360Z'}\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Backend: ibmq_qasm_simulator\n",
      "Highest probability outcome: 2\n"
     ]
    }
   ],
   "source": [
    "# we define the values\n",
    "a = 2\n",
    "b = 3                     \n",
    "N = 3\n",
    "\n",
    "# computing number of qubits n needed\n",
    "n = len(\"{0:b}\".format(a))\n",
    "n2 = len(\"{0:b}\".format(b))\n",
    "n3 = len(\"{0:b}\".format(N))\n",
    "if n2 > n:\n",
    "    n = n2\n",
    "if n3 > n:\n",
    "    n = n3\n",
    "    \n",
    "# classical register with n+1 bits.\n",
    "c = ClassicalRegister(n+1, name=\"cr\")\n",
    "# quantum registers\n",
    "qa = QuantumRegister(n, name=\"qa\") # a qubits\n",
    "qb = QuantumRegister(n+1, name=\"qb\") # b qubits\n",
    "qN = QuantumRegister(n+1, name=\"qN\") # N qubits\n",
    "qNtemp = QuantumRegister(n, name=\"qNtemp\") # temporary N qubits\n",
    "qtemp = QuantumRegister(1, name=\"qtemp\") # temporary qubit\n",
    "# if n = 1, no need of carry register \n",
    "if n == 1:\n",
    "    qcar = 0\n",
    "    # quantum circuit involving the quantum registers and the classical register\n",
    "    mod_add_circuit = QuantumCircuit(qa, qb, qN, qNtemp, qtemp,c, name=\"mod_add\")\n",
    "else:\n",
    "    qcar = QuantumRegister(n-1, name=\"qcar\") # carry qubits\n",
    "    # quantum circuit involving the quantum registers and the classical register\n",
    "    mod_add_circuit = QuantumCircuit(qa, qb, qN, qcar, qNtemp, qtemp, c, name=\"mod_add\")\n",
    "\n",
    "# create the state containing 'a'\n",
    "number_state(mod_add_circuit, qa, a, n)\n",
    "# create the state containing 'b'\n",
    "number_state(mod_add_circuit, qb, b, n)\n",
    "# create the state containing 'N'\n",
    "number_state(mod_add_circuit, qN, N, n)\n",
    "# create the temporary state containing 'N'\n",
    "number_state(mod_add_circuit, qNtemp, N, n)\n",
    "\n",
    "# modular addition\n",
    "mod_addition_nbit(mod_add_circuit, qa, qb, qN, qNtemp, qcar, qtemp, n)\n",
    "\n",
    "# measurements to see the result\n",
    "for i in range(n+1):\n",
    "    mod_add_circuit.measure(qb[i], c[i])\n",
    "\n",
    "# compile and execute the quantum program in the backend\n",
    "result = execute(mod_add_circuit, backend=backend, shots=1024).result()\n",
    "\n",
    "# show the results.\n",
    "print(result)\n",
    "print(result.get_data(\"mod_add\"))\n",
    "counts = result.get_counts(\"mod_add\")\n",
    "plot_histogram(counts)\n",
    "print(\"Backend:\", backend.name())\n",
    "print(\"Highest probability outcome: {}\".format(int(max(counts, key = lambda x: counts[x]).replace(\" \", \"\"), 2)))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Indeed the result is what we were expecting, $2\\, (010)$.\n",
    "\n",
    "## Controlled modular multiplication\n",
    "The modular multiplication can be implemented by repeated conditional additions modulo $N$: $ax = 2^0 ax_0 + 2^1 ax_1 + ... + 2^{n-1} ax_{n-1}$. We start from a register initiated in the state $|0\\rangle$. Then, the network consists in adding conditionally the value $2^i a$, depending on the state of the qubit $|x_i\\rangle$. Anyway, in order to implement the modular exponentiation, we need a more slightly complicated circuit, by the fact that we want the multiplication be effected conditionally depeding on the value of some external qubit $|c\\rangle$. If $|c\\rangle = |1\\rangle$\n",
    "\n",
    "\\begin{align}\n",
    "|c; x,0\\rangle \\, \\rightarrow \\,  |c;x, a \\times x\\; mod\\, N\\rangle \n",
    "\\end{align}\n",
    "\n",
    "This is done by applying Toffoli gates to $|x_i\\rangle$ and control qubits $|c\\rangle$ and the corresponding target qubit. The resetting of the register to its initial state is done by appliying the same Toffoli gates again. If the control qubit is $|0\\rangle$, no operations are done, giving the state $|c; x,0\\rangle$. Since we want the state to be $|c;x,x\\rangle$ we copy the values of the input register to the result register. This is done in the final part of the network. \n",
    "\n",
    "![Modular multiplication network](modular_multiplication_network1.png)\n",
    "\n",
    "However, this circuit requires that the value to be multiplied $a$ be hardwired into the circuit.\n",
    "\n",
    "\\begin{align}\n",
    "a \\times x = (a_{n-1} 2^{n-1} + ... + a_0 2^0)\\times (x_{n-1} 2^{n-1} + ... + x_0 2^0) = 2^{2n-2}(a_{n-1} x_{n-1}) + ...+ 2^{n-1}(a_0 x_{n-1} + a_1 x_{n-2} + .... + a_{n-2} x_1 + a_{n-1} x_0) + ... + 2^0 (a_0 x_0).\n",
    "\\end{align}\n",
    "\n",
    "Notice that the indices of each pair of qubits $a_i x_j$ indicate the respective power of $2$ ($2^{i+j}$). It is important to notice that $2^{i+j}$ can exceed our modulus N. Thus, we classicaly compute this value at each step and create a temporary register to hold these values.\n",
    "\n",
    "Summarizing, the controlled multiplication proceed as follows:\n",
    "1. We begin with $n$-qubits inputs $a$ and $x$ and examine each qubit individually. We apply a three-Toffoli gate to the qubits $a_i$ and $x_j$. If both qubits along with the control qubit are $|1\\rangle$ we XOR the incoming value $2^{i+j} \\, mod \\, N$ to the temporary register.\n",
    "2. The result is then fed into an addition modulo N module which adds the result to the register holding a running total. After this, the temporary register is set to $|0\\rangle$.\n",
    "\n",
    "The total number of qubits needed is $7n + 3$.\n",
    "\n",
    "\n",
    "### Implementation in the quantum simulator. Example 4.\n",
    "\n",
    "The fourth example is the implementation of the controlled modular multiplication of two $n$-qubit numbers $a$ and $x$. This program can be executed in the quantum simulator.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We define the same modules as in the modular addition, as well as the controlled modular multiplication algorithm for $n$-qubit numbers."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Use local qasm simulator\n",
    "backend = Aer.get_backend('qasm_simulator')\n",
    "\n",
    "# Use the IBM qasm simulator\n",
    "# backend = IBMQ.get_backend('ibmq_qasm_simulator')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "def carry(circuit, q0, q1, q2, q3):\n",
    "    \"carry module\"\n",
    "    circuit.ccx(q1, q2, q3)\n",
    "    circuit.cx(q1, q2)\n",
    "    circuit.ccx(q0, q2, q3)\n",
    "    \n",
    "def carry_inv(circuit, q0, q1, q2, q3):\n",
    "    \"carry module running backwards\"\n",
    "    circuit.ccx(q0, q2, q3)\n",
    "    circuit.cx(q1, q2)\n",
    "    circuit.ccx(q1, q2, q3)\n",
    "    \n",
    "def summation(circuit, q0, q1, q2):\n",
    "    \"summation module\"\n",
    "    circuit.cx(q1, q2)\n",
    "    circuit.cx(q0, q2)\n",
    "    \n",
    "def summation_inv(circuit, q0, q1, q2):\n",
    "    \"summation module running backwards\"\n",
    "    circuit.cx(q0, q2)\n",
    "    circuit.cx(q1, q2)\n",
    "\n",
    "# quantum plain addition algorithm for n-qubit numbers    \n",
    "def addition_nbit(circuit, qa, qb, qcar, n):\n",
    "    if n == 1:\n",
    "        circuit.ccx(qa[0], qb[0], qb[1])\n",
    "        circuit.cx(qa[0], qb[0])\n",
    "    else:\n",
    "        circuit.ccx(qa[0], qb[0], qcar[0])\n",
    "        circuit.cx(qa[0], qb[0])\n",
    "        for i in range(n-2):\n",
    "            carry(circuit, qcar[i], qa[i+1], qb[i+1], qcar[i+1])\n",
    "        carry(circuit, qcar[n-2], qa[n-1], qb[n-1], qb[n])\n",
    "        circuit.cx(qa[n-1], qb[n-1])\n",
    "        for i in range(n-1, 1, -1):\n",
    "            summation(circuit, qcar[i-1], qa[i], qb[i])\n",
    "            carry_inv(circuit, qcar[i-2], qa[i-1], qb[i-1], qcar[i-1])\n",
    "        summation(circuit, qcar[0], qa[1], qb[1])\n",
    "        circuit.cx(qa[0], qb[0])\n",
    "        circuit.ccx(qa[0], qb[0], qcar[0])\n",
    "        circuit.cx(qa[0], qb[0])\n",
    "    \n",
    "# quantum plain substraction algorithm for n-qubit numbers\n",
    "def subs_nbit(circuit, qa, qb, qcar, n):\n",
    "    \"same circuit as the addition but going backwards\"\n",
    "    if n == 1:\n",
    "        circuit.cx(qa[0], qb[0])\n",
    "        circuit.ccx(qa[0], qb[0], qb[1])\n",
    "    else:\n",
    "        circuit.cx(qa[0], qb[0])\n",
    "        circuit.ccx(qa[0], qb[0], qcar[0])\n",
    "        circuit.cx(qa[0], qb[0])\n",
    "        summation_inv(circuit, qcar[0], qa[1], qb[1])\n",
    "        for i in range(n-2):\n",
    "            carry(circuit, qcar[i], qa[i+1], qb[i+1], qcar[i+1])\n",
    "            summation_inv(circuit, qcar[i+1], qa[i+2], qb[i+2])\n",
    "        circuit.cx(qa[n-1], qb[n-1])\n",
    "        carry_inv(circuit, qcar[n-2], qa[n-1], qb[n-1], qb[n])\n",
    "        for i in range(n-2, 0, -1):\n",
    "            carry_inv(circuit, qcar[i-1], qa[i], qb[i], qcar[i])\n",
    "        circuit.cx(qa[0], qb[0])  \n",
    "        circuit.ccx(qa[0], qb[0], qcar[0])\n",
    "\n",
    "def cond_toffoli(circuit, qcond, q1, q2, q3):\n",
    "    \"toffoli gate conditioned by an external qubit\"\n",
    "    circuit.h(q3)\n",
    "    circuit.ccx(qcond, q2, q3)\n",
    "    circuit.tdg(q3)\n",
    "    circuit.ccx(qcond, q1, q3)\n",
    "    circuit.t(q3)\n",
    "    circuit.ccx(qcond, q2, q3)\n",
    "    circuit.tdg(q3)\n",
    "    circuit.ccx(qcond, q1, q3)\n",
    "    circuit.t(q3)\n",
    "    circuit.h(q3)\n",
    "    circuit.t(q2)\n",
    "    circuit.ccx(qcond, q1, q2)\n",
    "    circuit.t(q1)\n",
    "    circuit.tdg(q2)\n",
    "    circuit.ccx(qcond, q1, q2)\n",
    "    \n",
    "def cond_carry(circuit, q0, q1, q2, q3, qcond):\n",
    "    \"conditional carry module\"\n",
    "    cond_toffoli(circuit, qcond, q1, q2, q3)\n",
    "    circuit.ccx(qcond, q1, q2)\n",
    "    cond_toffoli(circuit, qcond, q0, q2, q3)\n",
    "    \n",
    "def cond_carry_inv(circuit, q0, q1, q2, q3, qcond):\n",
    "    \"conditional carry module running backwards\"\n",
    "    cond_toffoli(circuit, qcond, q0, q2, q3)\n",
    "    circuit.ccx(qcond, q1, q2)\n",
    "    cond_toffoli(circuit, qcond, q1, q2, q3)\n",
    "    \n",
    "def cond_summation(circuit, q0, q1, q2, qcond):\n",
    "    \"conditional summation module\"\n",
    "    circuit.ccx(qcond, q1, q2)\n",
    "    circuit.ccx(qcond, q0, q2)\n",
    "    \n",
    "def cond_summation_inv(circuit, q0, q1, q2, qcond):\n",
    "    \"conditional summation module running backwards\"\n",
    "    circuit.ccx(qcond, q0, q2)\n",
    "    circuit.ccx(qcond, q1, q2)\n",
    "    \n",
    "# quantum conditional plain addition algorithm for n-qubit numbers    \n",
    "def cond_addition_nbit(circuit, qa, qb, qcar, qcond, n):\n",
    "    if n == 1:\n",
    "        cond_toffoli(circuit, qcond, qa[0], qb[0], qb[1])\n",
    "        circuit.ccx(qcond, qa[0], qb[0])\n",
    "    else:\n",
    "        cond_toffoli(circuit, qcond, qa[0], qb[0], qcar[0])\n",
    "        circuit.ccx(qcond, qa[0], qb[0])\n",
    "        for i in range(n-2):\n",
    "            cond_carry(circuit, qcar[i], qa[i+1], qb[i+1], qcar[i+1], qcond)\n",
    "        cond_carry(circuit, qcar[n-2], qa[n-1], qb[n-1], qb[n], qcond)\n",
    "        circuit.ccx(qcond, qa[n-1], qb[n-1])\n",
    "        for i in range(n-1, 1, -1):\n",
    "            cond_summation(circuit, qcar[i-1], qa[i], qb[i], qcond)\n",
    "            cond_carry_inv(circuit, qcar[i-2], qa[i-1], qb[i-1], qcar[i-1], qcond)\n",
    "        cond_summation(circuit, qcar[0], qa[1], qb[1], qcond)\n",
    "        circuit.ccx(qcond, qa[0], qb[0])\n",
    "        cond_toffoli(circuit, qcond, qa[0], qb[0], qcar[0])\n",
    "        circuit.ccx(qcond, qa[0], qb[0])\n",
    "\n",
    "# quantum conditional plain substraction algorithm for n-qubit numbers      \n",
    "def cond_subs_nbit(circuit, qa, qb, qcar, qcond, n):\n",
    "    \"same circuit as the conditional plain addition but going backwards\"\n",
    "    if n == 1:\n",
    "        circuit.ccx(qcond, qa[0], qb[0])\n",
    "        cond_toffoli(circuit, qcond, qa[0], qb[0], qb[1])\n",
    "    else:\n",
    "        circuit.ccx(qcond, qa[0], qb[0])\n",
    "        cond_toffoli(circuit, qcond, qa[0], qb[0], qcar[0])\n",
    "        circuit.ccx(qcond, qa[0], qb[0])\n",
    "        cond_summation_inv(circuit, qcar[0], qa[1], qb[1], qcond)\n",
    "        for i in range(n-2):\n",
    "            cond_carry(circuit, qcar[i], qa[i+1], qb[i+1], qcar[i+1], qcond)\n",
    "            cond_summation_inv(circuit, qcar[i+1], qa[i+2], qb[i+2], qcond)\n",
    "        circuit.ccx(qcond, qa[n-1], qb[n-1])\n",
    "        cond_carry_inv(circuit, qcar[n-2], qa[n-1], qb[n-1], qb[n], qcond)\n",
    "        for i in range(n-2, 0, -1):\n",
    "            cond_carry_inv(circuit, qcar[i-1], qa[i], qb[i], qcar[i], qcond)\n",
    "        circuit.ccx(qcond, qa[0], qb[0])  \n",
    "        cond_toffoli(circuit, qcond, qa[0], qb[0], qcar[0])\n",
    "        \n",
    "# quantum modular addition algorithm for n-qubit numbers \n",
    "def mod_addition_nbit(circuit, qa, qb, qN, qNtemp, qcar, qtemp, n):\n",
    "    addition_nbit(circuit, qa, qb, qcar, n)\n",
    "    subs_nbit(circuit, qN, qb, qcar, n)\n",
    "    circuit.x(qb[n])\n",
    "    circuit.cx(qb[n], qtemp)\n",
    "    circuit.x(qb[n])\n",
    "    cond_subs_nbit(circuit, qNtemp, qN, qcar, qtemp, n)\n",
    "    addition_nbit(circuit, qN, qb, qcar, n)\n",
    "    cond_addition_nbit(circuit, qNtemp, qN, qcar, qtemp, n)\n",
    "    subs_nbit(circuit, qa, qb, qcar, n)\n",
    "    circuit.cx(qb[n], qtemp)\n",
    "    addition_nbit(circuit, qa, qb, qcar, n)\n",
    "    \n",
    "# quantum controlled modular multiplication algorithm for n-qubit numbers\n",
    "def cont_mod_mult_nbit(circuit, qa, qb, qN, qNtemp, qcar, qtemp, qtempst, qX, qext, N, n):\n",
    "    for i in range(n):\n",
    "        for j in range(n):\n",
    "            classical_mod = (2**(i+j))%N\n",
    "            cond_number_state(circuit, qtempst, classical_mod, qext, qa[i], qX[j], n)\n",
    "            mod_addition_nbit(circuit, qtempst, qb, qN, qNtemp, qcar, qtemp, n)\n",
    "            cond_number_state(circuit, qtempst, classical_mod, qext, qa[i], qX[j], n)\n",
    "    circuit.x(qext)\n",
    "    cond_addition_nbit(circuit, qX, qb, qcar, qext, n)\n",
    "    circuit.x(qext)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We define the function that creates the different states. This time we also define another function, what does essentially the same, but controlled by 3 control qubits. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "# n-qubit number input state\n",
    "def number_state(circuit, q, x, n):\n",
    "    # integer to binary\n",
    "    x = \"{0:b}\".format(x)\n",
    "    x = x.zfill(n)\n",
    "    # creating the state\n",
    "    for i in range(n):\n",
    "        if int(x[n-1-i]) == 1:\n",
    "            circuit.x(q[i])\n",
    "\n",
    "# n-qubit number input state, controlled by 2 control qubits\n",
    "def cond_number_state(circuit, q, x, ext, control1, control2, n):\n",
    "    # integer to binary\n",
    "    x = \"{0:b}\".format(x)\n",
    "    x = x.zfill(n)\n",
    "    # creating the state\n",
    "    for i in range(n):\n",
    "        if int(x[n-1-i]) == 1:\n",
    "            cond_toffoli(circuit, ext, control1, control2, q[i])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's implement now the controlled modular multiplication of two numbers $a \\times x \\, mod \\, N$, for instance $1 \\times 1 \\,mod\\, 1$ (in order to avoid long computing times, but you can try with two-qubit numbers), that should return $0 \\, (00$), if the control qubit is $|1\\rangle$ (otherwise the result would be $1 \\, (01)$):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "COMPLETED\n",
      "{'creg_labels': 'cr[2]', 'additionalData': {'seed': 136383785}, 'versionSimulationRun': 'IBM_Q_Simulator:CPU-v0.1.b5cdd73\\n', 'time': 9.94355, 'counts': {'00': 1024}, 'date': '2018-10-12T19:10:38.038Z'}\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Backend: ibmq_qasm_simulator\n",
      "Highest probability outcome: 0\n"
     ]
    }
   ],
   "source": [
    "# we define the values\n",
    "a = 1\n",
    "x = 1\n",
    "N = 1\n",
    "\n",
    "\n",
    "# computing number of qubits n needed\n",
    "n = len(\"{0:b}\".format(a))\n",
    "n2 = len(\"{0:b}\".format(x))\n",
    "n3 = len(\"{0:b}\".format(N))\n",
    "if n2 > n:\n",
    "    n = n2\n",
    "if n3 > n:\n",
    "    n = n3\n",
    "\n",
    "# classical register with n+1 bits.\n",
    "c = ClassicalRegister(n+1, name=\"cr\")\n",
    "# quantum registers\n",
    "qa = QuantumRegister(n, name=\"qa\") # a qubits\n",
    "qb = QuantumRegister(n+1, name=\"qb\") # result register\n",
    "qN = QuantumRegister(n+1, name=\"qN\") # N qubits\n",
    "qNtemp = QuantumRegister(n, name=\"qNtemp\") # temporary N qubits\n",
    "qtemp = QuantumRegister(1, name=\"qtemp\") # temporary qubit\n",
    "qtempst = QuantumRegister(n, name=\"qtempst\") # temporary register\n",
    "qX = QuantumRegister(n, name=\"qX\") # x register\n",
    "qext = QuantumRegister(1, name=\"qext\")\n",
    "# if n = 1, no need of carry register \n",
    "if n == 1:\n",
    "    qcar = 0\n",
    "    # quantum circuit involving the quantum registers and the classical register\n",
    "    mod_mult_circuit = QuantumCircuit(qa, qb, qN, qNtemp, qtemp, qtempst, qX, qext, c, name=\"mod_mult\")\n",
    "else:\n",
    "    qcar = QuantumRegister(n-1, name=\"qcar\") # carry qubits\n",
    "    # quantum circuit involving the quantum register and the classical register\n",
    "    mod_mult_circuit = QuantumCircuit(qa, qb, qN, qcar, qNtemp, qtemp, qtempst, qX, qext, c, name=\"mod_mult\")\n",
    "\n",
    "# create the state containing 'a'\n",
    "number_state(mod_mult_circuit, qa, a, n)\n",
    "# create the state containing 'b'\n",
    "number_state(mod_mult_circuit, qX, x, n)\n",
    "# create the state containing 'N'\n",
    "number_state(mod_mult_circuit, qN, N, n+1)\n",
    "# create a temporary state containing 'N'\n",
    "number_state(mod_mult_circuit, qNtemp, N, n)\n",
    "\n",
    "mod_mult_circuit.x(qext[0]) # we set the control qubit to |1>\n",
    "\n",
    "# controlled modular multiplication\n",
    "cont_mod_mult_nbit(mod_mult_circuit, qa, qb, qN, qNtemp, qcar, qtemp[0], qtempst, qX, qext[0], N, n)\n",
    "\n",
    "# measurements to see the result\n",
    "for i in range(n+1):\n",
    "    mod_mult_circuit.measure(qb[i], c[i])\n",
    "\n",
    "# compile and execute the quantum program in the backend\n",
    "result = execute(mod_mult_circuit, backend=backend, shots=1024).result()\n",
    "\n",
    "# show the results.\n",
    "print(result)\n",
    "print(result.get_data(mod_mult_circuit))\n",
    "counts = result.get_counts(mod_mult_circuit)\n",
    "plot_histogram(counts)\n",
    "print(\"Backend:\", backend.name())\n",
    "print(\"Highest probability outcome: {}\".format(int(max(counts, key = lambda x: counts[x]).replace(\" \", \"\"), 2)))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We indeed obtain the expected result $0 \\, (00)$.\n",
    "\n",
    "## Modular exponentiation\n",
    "Using the previous constructions, we can finally implement the exponentiation modulo $N$: $a^x \\,mod \\,N$. The value $a^x$ can be written as $a^x = a^{2^{0}x_0} · a^{2^{1}x_1} · ... · a^{2^{m-1}x_{m-1}}$. The modular exponentiation can be implemented by initially setting a register to $|1\\rangle$ and then effecting $n$ modular multiplications by $a^{2^i}$ depending on the value of the qubit $|x_i\\rangle$. Let's look into the operations carefully. If $x_i = 1$:\n",
    "\n",
    "\\begin{align}\n",
    "|a^{2^{0}x_{0} + ... + 2^{i-1}x_{i-1}}, 0 \\rangle \\;\\rightarrow\\; |a^{2^{0}x_{0} + ... + 2^{i-1}x_{i-1}}, a^{2^{0}x_{0} + ... + 2^{i-1}x_{i-1}} · a^{2^i}\\rangle \n",
    "\\end{align}\n",
    "\n",
    "otherwise, if $x_i = 0$:\n",
    "\n",
    "\\begin{align}\n",
    "|a^{2^{0}x_{0} + ... + 2^{i-1}x_{i-1}}, 0 \\rangle \\;\\rightarrow\\; |a^{2^{0}x_{0} + ... + 2^{i-1}x_{i-1}}, a^{2^{0}x_{0} + ... + 2^{i-1}x_{i-1}}\\rangle \\,.\n",
    "\\end{align}\n",
    "\n",
    "In both cases the result can be written as $|a^{2^{0}x_{0} + ... + 2^{i-1}x_{i-1}}, a^{2^{0}x_{0} + ... + 2^{i}x_{i}}\\rangle$. We must take care about the accumulation of intermediate data. To avoid this partial information generated we run backwards a controlled multiplication network with the value $a^{-2^i} \\,mod\\, N$. This quantity is precomputed classically, but $a$ and $N$ must be coprimes.\n",
    "\n",
    "The total number of qubits needed is $7n + 3 + n_x$, where $n_x$ are the number of qubits of the value $x$. \n",
    "\n",
    "![Modular exponentiation network](modular_exponentiation_network1.png)\n",
    "\n",
    "### Implementation in the quantum simulator. Example 5.\n",
    "\n",
    "As you may expect, we do not want to finish this Qiskit tutorial of basic arithmetic operations without the keystone of the Shor's factorization algorithm. The final example is the implementation of the modular exponentiation $a^x \\; mod\\, N$. This program can be executed in the quantum simulator."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "This time we have to run backwards the controlled modular multiplication block, therefore we will need to define new modules such as running backwards the modular addition."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Use local qasm simulator\n",
    "backend = Aer.get_backend('qasm_simulator')\n",
    "\n",
    "# Use the IBM qasm simulator\n",
    "# backend = IBMQ.get_backend('ibmq_qasm_simulator')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [],
   "source": [
    "def carry(circuit, q0, q1, q2, q3):\n",
    "    \"carry module\"\n",
    "    circuit.ccx(q1, q2, q3)\n",
    "    circuit.cx(q1, q2)\n",
    "    circuit.ccx(q0, q2, q3)\n",
    "    \n",
    "def carry_inv(circuit, q0, q1, q2, q3):\n",
    "    \"carry module running backwards\"\n",
    "    circuit.ccx(q0, q2, q3)\n",
    "    circuit.cx(q1, q2)\n",
    "    circuit.ccx(q1, q2, q3)\n",
    "    \n",
    "def summation(circuit, q0, q1, q2):\n",
    "    \"summation module\"\n",
    "    circuit.cx(q1, q2)\n",
    "    circuit.cx(q0, q2)\n",
    "    \n",
    "def summation_inv(circuit, q0, q1, q2):\n",
    "    \"summation module running backwards\"\n",
    "    circuit.cx(q0, q2)\n",
    "    circuit.cx(q1, q2)\n",
    "\n",
    "# quantum plain addition algorithm for n-qubit numbers    \n",
    "def addition_nbit(circuit, qa, qb, qcar, n):\n",
    "    if n == 1:\n",
    "        circuit.ccx(qa[0], qb[0], qb[1])\n",
    "        circuit.cx(qa[0], qb[0])\n",
    "    else:\n",
    "        circuit.ccx(qa[0], qb[0], qcar[0])\n",
    "        circuit.cx(qa[0], qb[0])\n",
    "        for i in range(n-2):\n",
    "            carry(circuit, qcar[i], qa[i+1], qb[i+1], qcar[i+1])\n",
    "        carry(circuit, qcar[n-2], qa[n-1], qb[n-1], qb[n])\n",
    "        circuit.cx(qa[n-1], qb[n-1])\n",
    "        for i in range(n-1, 1, -1):\n",
    "            summation(circuit, qcar[i-1], qa[i], qb[i])\n",
    "            carry_inv(circuit, qcar[i-2], qa[i-1], qb[i-1], qcar[i-1])\n",
    "        summation(circuit, qcar[0], qa[1], qb[1])\n",
    "        circuit.cx(qa[0], qb[0])\n",
    "        circuit.ccx(qa[0], qb[0], qcar[0])\n",
    "        circuit.cx(qa[0], qb[0])\n",
    "    \n",
    "# quantum plain substraction algorithm for n-qubit numbers \n",
    "def subs_nbit(circuit, qa, qb, qcar, n):\n",
    "    \"same as the plain addition but running backwards\"\n",
    "    if n == 1:\n",
    "        circuit.cx(qa[0], qb[0])\n",
    "        circuit.ccx(qa[0], qb[0], qb[1])\n",
    "    else:\n",
    "        circuit.cx(qa[0], qb[0])\n",
    "        circuit.ccx(qa[0], qb[0], qcar[0])\n",
    "        circuit.cx(qa[0], qb[0])\n",
    "        summation_inv(circuit, qcar[0], qa[1], qb[1])\n",
    "        for i in range(n-2):\n",
    "            carry(circuit, qcar[i], qa[i+1], qb[i+1], qcar[i+1])\n",
    "            summation_inv(circuit, qcar[i+1], qa[i+2], qb[i+2])\n",
    "        circuit.cx(qa[n-1], qb[n-1])\n",
    "        carry_inv(circuit, qcar[n-2], qa[n-1], qb[n-1], qb[n])\n",
    "        for i in range(n-2, 0, -1):\n",
    "            carry_inv(circuit, qcar[i-1], qa[i], qb[i], qcar[i])\n",
    "        circuit.cx(qa[0], qb[0])  \n",
    "        circuit.ccx(qa[0], qb[0], qcar[0])\n",
    "        \n",
    "def cond_toffoli(circuit, qcond, q1, q2, q3):\n",
    "    \"conditional toffoli gate\"\n",
    "    circuit.h(q3)\n",
    "    circuit.ccx(qcond, q2, q3)\n",
    "    circuit.tdg(q3)\n",
    "    circuit.ccx(qcond, q1, q3)\n",
    "    circuit.t(q3)\n",
    "    circuit.ccx(qcond, q2, q3)\n",
    "    circuit.tdg(q3)\n",
    "    circuit.ccx(qcond, q1, q3)\n",
    "    circuit.t(q3)\n",
    "    circuit.h(q3)\n",
    "    circuit.t(q2)\n",
    "    circuit.ccx(qcond, q1, q2)\n",
    "    circuit.t(q1)\n",
    "    circuit.tdg(q2)\n",
    "    circuit.ccx(qcond, q1, q2)\n",
    "\n",
    "def cond_carry(circuit, q0, q1, q2, q3, qcond):\n",
    "    \"conditional carry module\"\n",
    "    cond_toffoli(circuit, qcond, q1, q2, q3)\n",
    "    circuit.ccx(qcond, q1, q2)\n",
    "    cond_toffoli(circuit, qcond, q0, q2, q3)\n",
    "    \n",
    "def cond_carry_inv(circuit, q0, q1, q2, q3, qcond):\n",
    "    \"conditional carry module running backwards\"\n",
    "    cond_toffoli(circuit, qcond, q0, q2, q3)\n",
    "    circuit.ccx(qcond, q1, q2)\n",
    "    cond_toffoli(circuit, qcond, q1, q2, q3)\n",
    "    \n",
    "def cond_summation(circuit, q0, q1, q2, qcond):\n",
    "    \"conditional summation\"\n",
    "    circuit.ccx(qcond, q1, q2)\n",
    "    circuit.ccx(qcond, q0, q2)\n",
    "    \n",
    "def cond_summation_inv(circuit, q0, q1, q2, qcond):\n",
    "    \"conditional summation running backwards\"\n",
    "    circuit.ccx(qcond, q0, q2)\n",
    "    circuit.ccx(qcond, q1, q2)\n",
    "    \n",
    "# quantum conditional plain addition algorithm for n-qubit numbers    \n",
    "def cond_addition_nbit(circuit, qa, qb, qcar, qcond, n):\n",
    "    if n == 1:\n",
    "        cond_toffoli(circuit, qcond, qa[0], qb[0], qb[1])\n",
    "        circuit.ccx(qcond, qa[0], qb[0])\n",
    "    else:\n",
    "        cond_toffoli(circuit, qcond, qa[0], qb[0], qcar[0])\n",
    "        circuit.ccx(qcond, qa[0], qb[0])\n",
    "        for i in range(n-2):\n",
    "            cond_carry(circuit, qcar[i], qa[i+1], qb[i+1], qcar[i+1], qcond)\n",
    "        cond_carry(circuit, qcar[n-2], qa[n-1], qb[n-1], qb[n], qcond)\n",
    "        circuit.ccx(qcond, qa[n-1], qb[n-1])\n",
    "        for i in range(n-1, 1, -1):\n",
    "            cond_summation(circuit, qcar[i-1], qa[i], qb[i], qcond)\n",
    "            cond_carry_inv(circuit, qcar[i-2], qa[i-1], qb[i-1], qcar[i-1], qcond)\n",
    "        cond_summation(circuit, qcar[0], qa[1], qb[1], qcond)\n",
    "        circuit.ccx(qcond, qa[0], qb[0])\n",
    "        cond_toffoli(circuit, qcond, qa[0], qb[0], qcar[0])\n",
    "        circuit.ccx(qcond, qa[0], qb[0])\n",
    "\n",
    "# quantum conditional plain substraction algorithm for n-qubit numbers      \n",
    "def cond_subs_nbit(circuit, qa, qb, qcar, qcond, n):\n",
    "    \"same as conditional plain addition but running backwards\"\n",
    "    if n == 1:\n",
    "        circuit.ccx(qcond, qa[0], qb[0])\n",
    "        cond_toffoli(circuit, qcond, qa[0], qb[0], qb[1])\n",
    "    else:\n",
    "        circuit.ccx(qcond, qa[0], qb[0])\n",
    "        cond_toffoli(circuit, qcond, qa[0], qb[0], qcar[0])\n",
    "        circuit.ccx(qcond, qa[0], qb[0])\n",
    "        cond_summation_inv(circuit, qcar[0], qa[1], qb[1], qcond)\n",
    "        for i in range(n-2):\n",
    "            cond_carry(circuit, qcar[i], qa[i+1], qb[i+1], qcar[i+1], qcond)\n",
    "            cond_summation_inv(circuit, qcar[i+1], qa[i+2], qb[i+2], qcond)\n",
    "        circuit.ccx(qcond, qa[n-1], qb[n-1])\n",
    "        cond_carry_inv(circuit, qcar[n-2], qa[n-1], qb[n-1], qb[n], qcond)\n",
    "        for i in range(n-2, 0, -1):\n",
    "            cond_carry_inv(circuit, qcar[i-1], qa[i], qb[i], qcar[i], qcond)\n",
    "        circuit.ccx(qcond, qa[0], qb[0])  \n",
    "        cond_toffoli(circuit, qcond, qa[0], qb[0], qcar[0])\n",
    "        \n",
    "# quantum modular addition algorithm for n-qubit numbers \n",
    "def mod_addition_nbit(circuit, qa, qb, qN, qNtemp, qcar, qtemp, n):\n",
    "    addition_nbit(circuit, qa, qb, qcar, n)\n",
    "    subs_nbit(circuit, qN, qb, qcar, n)\n",
    "    circuit.x(qb[n])\n",
    "    circuit.cx(qb[n], qtemp)\n",
    "    circuit.x(qb[n])\n",
    "    cond_subs_nbit(circuit, qNtemp, qN, qcar, qtemp, n)\n",
    "    addition_nbit(circuit, qN, qb, qcar, n)\n",
    "    cond_addition_nbit(circuit, qNtemp, qN, qcar, qtemp, n)\n",
    "    subs_nbit(circuit, qa, qb, qcar, n)\n",
    "    circuit.cx(qb[n], qtemp)\n",
    "    addition_nbit(circuit, qa, qb, qcar, n)\n",
    "    \n",
    "# quantum modular substraction algorithm for n-qubit numbers\n",
    "def mod_subs_nbit(circuit, qa, qb, qN, qNtemp, qcar, qtemp, n):\n",
    "    \"same as modular addition but running backwards\"\n",
    "    subs_nbit(circuit, qa, qb, qcar, n)\n",
    "    circuit.cx(qb[n], qtemp)\n",
    "    addition_nbit(circuit, qa, qb, qcar, n)\n",
    "    cond_subs_nbit(circuit, qNtemp, qN, qcar, qtemp, n)\n",
    "    subs_nbit(circuit, qN, qb, qcar, n)\n",
    "    cond_addition_nbit(circuit, qNtemp, qN, qcar, qtemp, n)\n",
    "    circuit.x(qb[n])\n",
    "    circuit.cx(qb[n], qtemp)\n",
    "    circuit.x(qb[n])\n",
    "    addition_nbit(circuit, qN, qb, qcar, n)\n",
    "    subs_nbit(circuit, qa, qb, qcar, n)\n",
    "\n",
    "# quantum controlled modular multiplication algorithm for n-qubit numbers\n",
    "def cont_mod_mult_nbit(circuit, qa, qb, qN, qNtemp, qcar, qtemp, qtempst, qX, qext, N, n):\n",
    "    for i in range(n):\n",
    "        for j in range(n):\n",
    "            classical_mod = (2**(i+j))%N\n",
    "            cond_number_state(circuit, qtempst, classical_mod, qext, qa[i], qX[j], n)\n",
    "            mod_addition_nbit(circuit, qtempst, qb, qN, qNtemp, qcar, qtemp, n)\n",
    "            cond_number_state(circuit, qtempst, classical_mod, qext, qa[i], qX[j], n)\n",
    "    circuit.x(qext)\n",
    "    cond_addition_nbit(circuit, qX, qb, qcar, qext, n)\n",
    "    circuit.x(qext)\n",
    "\n",
    "def cont_inv_mod_mult_nbit(circuit, qa, qb, qN, qNtemp, qcar, qtemp, qtempst, qX, qext, N, n):\n",
    "    \"same as the controlled modular multiplication but running backwards\"\n",
    "    circuit.x(qext)\n",
    "    cond_subs_nbit(circuit, qX, qb, qcar, qext, n)\n",
    "    circuit.x(qext)\n",
    "    for i in range(n):\n",
    "        for j in range(n):\n",
    "            classical_mod = (2**(i+j))%N\n",
    "            cond_number_state(circuit, qtempst, classical_mod, qext, qa[i], qX[j], n)\n",
    "            mod_subs_nbit(circuit, qtempst, qb, qN, qNtemp, qcar, qtemp, n)\n",
    "            cond_number_state(circuit, qtempst, classical_mod, qext, qa[i], qX[j], n)\n",
    "\n",
    "# quantum modular exponentiation algorithm for n-qubit numbers\n",
    "def mod_exp_nbit(circuit, qa, qb, qN, qNtemp, qcar, qtemp, qtempst, q1, qX, N, a, n):\n",
    "    for k in range(len(qX)):\n",
    "        clas_value = (a**(2**(k)))%N\n",
    "        if k % 2 == 0:\n",
    "            number_state(circuit, qa, clas_value, n)\n",
    "            cont_mod_mult_nbit(circuit, qa, qb, qN, qNtemp, qcar, qtemp, qtempst, q1, qX[k], N, n)\n",
    "            number_state(circuit, qa, clas_value, n)\n",
    "            clas_value = modinv(a**(2**(k)), N)\n",
    "            number_state(circuit, qa, clas_value, n)\n",
    "            cont_inv_mod_mult_nbit(circuit, qa, q1, qN, qNtemp, qcar, qtemp, qtempst, qb, qX[k], N, n)\n",
    "            number_state(circuit, qa, clas_value, n)\n",
    "        else:\n",
    "            number_state(circuit, qa, clas_value, n)\n",
    "            cont_mod_mult_nbit(circuit, qa, q1, qN, qNtemp, qcar, qtemp, qtempst, qb, qX[k], N, n)\n",
    "            number_state(circuit, qa, clas_value, n)\n",
    "            clas_value = modinv(a**(2**(k)), N)\n",
    "            number_state(circuit, qa, clas_value, n)\n",
    "            cont_inv_mod_mult_nbit(circuit, qa, qb, qN, qNtemp, qcar, qtemp, qtempst, q1, qX[k], N, n)\n",
    "            number_state(circuit, qa, clas_value, n)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We define the function that creates the different states. This time we also define another two functions, which compute the value of the modular multiplicative inverse $a^{-1} \\, mod \\, m$. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [],
   "source": [
    "# n-qubit number input state\n",
    "def number_state(circuit, q, x, n):\n",
    "    # integer to binary\n",
    "    x = \"{0:b}\".format(x)\n",
    "    x = x.zfill(n)\n",
    "    # creating the state\n",
    "    for i in range(n):\n",
    "        if int(x[n-1-i]) == 1:\n",
    "            circuit.x(q[i])\n",
    "\n",
    "# n-qubit number input state, controlled by 2 control qubits\n",
    "def cond_number_state(circuit, q, x, ext, control1, control2, n):\n",
    "    # integer to binary\n",
    "    x = \"{0:b}\".format(x)\n",
    "    x = x.zfill(n)\n",
    "    # creating the state\n",
    "    for i in range(n):\n",
    "        if int(x[n-1-i]) == 1:\n",
    "            cond_toffoli(circuit, ext, control1, control2, q[i])\n",
    "\n",
    "# efficient algorithm for computing the modular multiplicative inverse a^-1 mod m\n",
    "def egcd(a, b):\n",
    "    if a == 0:\n",
    "        return (b, 0, 1)\n",
    "    else:\n",
    "        g, y, x = egcd(b % a, a)\n",
    "        return (g, x - (b // a) * y, y)\n",
    "\n",
    "def modinv(a, m):\n",
    "    g, x, y = egcd(a, m)\n",
    "    if g != 1:\n",
    "        raise Exception('modular inverse does not exist')\n",
    "    else:\n",
    "        return x % m"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's implement now the modular exponentiation of two $n$-qubit numbers $a$ and $N$ ($a^x \\, mod \\, N$), for instance $1^1 \\,mod\\, 1$ (in order to avoid long computing times, but you can try with two-qubit numbers), that should return $0 \\, (00)$:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "COMPLETED\n",
      "{'creg_labels': 'cr[2]', 'additionalData': {'seed': 1072014857}, 'versionSimulationRun': 'IBM_Q_Simulator:CPU-v0.1.b5cdd73\\n', 'time': 19.2835, 'counts': {'00': 1024}, 'date': '2018-10-12T19:11:30.104Z'}\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Backend: ibmq_qasm_simulator\n",
      "Highest probability outcome: 0\n"
     ]
    }
   ],
   "source": [
    "# we define the values, a and N must be coprimes\n",
    "a = 1\n",
    "x = 1\n",
    "N = 1\n",
    "\n",
    "\n",
    "# computing number of qubits n needed\n",
    "n = len(\"{0:b}\".format(a))\n",
    "n2 = len(\"{0:b}\".format(x))\n",
    "n3 = len(\"{0:b}\".format(N))\n",
    "\n",
    "if n3 > n:\n",
    "    n = n3\n",
    "\n",
    "# classical register with n+1 bits.\n",
    "c = ClassicalRegister(n+1, name=\"cr\")\n",
    "# quantum registers\n",
    "qa = QuantumRegister(n, name=\"qa\") # a qubits\n",
    "qb = QuantumRegister(n+1, name=\"qb\") # initial state |0>\n",
    "qN = QuantumRegister(n+1, name=\"qN\") # N qubits\n",
    "qNtemp = QuantumRegister(n, name=\"qNtemp\") # temporary N qubits\n",
    "qtemp = QuantumRegister(1, name=\"qtemp\") # temporary qubit\n",
    "qtempst = QuantumRegister(n, name=\"qtempst\") # temporary register\n",
    "q1 = QuantumRegister(n+1, name=\"q1\") # initial state |1>\n",
    "qX = QuantumRegister(n2, name=\"qX\") # x register\n",
    "# if n = 1, no need of carry register \n",
    "if n == 1:\n",
    "    qcar = 0\n",
    "    # quantum circuit involving the quantum registers and the classical register\n",
    "    mod_exp_circuit = QuantumCircuit(qa, qb, qN, qNtemp, qtemp, qtempst, q1, qX, c, name=\"mod_exp\")\n",
    "else:\n",
    "    qcar =QuantumCircuit(n-1, name=\"qcar\") # carry qubits\n",
    "    # quantum circuit involving the quantum registers and the classical register\n",
    "    mod_exp_circuit = QuantumCircuit(qa, qb, qN, qcar, qNtemp, qtemp, qtempst, q1, qX, c, name=\"mod_exp\")                       \n",
    "\n",
    "# create the initial state |1>. If N = 1, initial state is |0>\n",
    "if N != 1:\n",
    "    number_state(mod_exp_circuit, q1, 1, 1)\n",
    "# create the state containing 'x'\n",
    "number_state(mod_exp_circuit, qX, x, n2)\n",
    "# create the state containing 'N'\n",
    "number_state(mod_exp_circuit, qN, N, n+1)\n",
    "# create a temporary state containing 'N'\n",
    "number_state(mod_exp_circuit, qNtemp, N, n)\n",
    "\n",
    "# modular exponentiation\n",
    "mod_exp_nbit(mod_exp_circuit, qa, qb, qN, qNtemp, qcar, qtemp[0], qtempst, q1, qX, N, a, n)\n",
    "\n",
    "# measurements to see the result, the result would be in one of those registers, q1 or qb\n",
    "if n2 % 2 == 0:\n",
    "    for i in range(n+1):\n",
    "        mod_exp_circuit.measure(q1[i], c[i])\n",
    "else:\n",
    "    for i in range(n+1):\n",
    "        mod_exp_circuit.measure(qb[i], c[i])\n",
    "\n",
    "# compile and execute the quantum program in the backend\n",
    "result = execute(mod_exp_circuit, backend=backend, shots=1024).result()\n",
    "\n",
    "# show the results.\n",
    "print(result)\n",
    "print(result.get_data(mod_exp_circuit))\n",
    "counts = result.get_counts(mod_exp_circuit)\n",
    "plot_histogram(counts)\n",
    "print(\"Backend:\", backend.name())\n",
    "print(\"Highest probability outcome: {}\".format(int(max(counts, key = lambda x: counts[x]).replace(\" \", \"\"), 2)))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We indeed have obtained the expected result $0 \\, (00)$."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
